package com.sunfeng.jksj.p18;

import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.StampedLock;

/**
 * @Author : 孙峰
 * @Description:
 * @Date : 2022/1/25  8:56
 */
public class Test01 {
    public static void main(String[] args) throws InterruptedException {


    }

    /**
     * 如果线程阻塞在 StampedLock 的 readLock() 或者 writeLock() 上时，此时调用该阻塞线程的 interrupt() 方法，会导致 CPU 飙升。例如下面的代码中，
     * 线程 T1 获取写锁之后将自己阻塞，线程 T2 尝试获取悲观读锁，也会阻塞；如果此时调用线程 T2 的 interrupt() 方法来中断线程 T2 的话，你会发现线程 T2 所在 CPU 会飙升到 100%。
     *
     * @throws InterruptedException
     */
    public static void test01() throws InterruptedException {
        final StampedLock lock
                = new StampedLock();
        Thread T1 = new Thread(() -> {
            // 获取写锁
            lock.writeLock();
            // 永远阻塞在此处，不释放写锁
            LockSupport.park();
        }, "线程1");
        T1.start();
        // 保证T1获取写锁
        Thread.sleep(100);
        //阻塞在悲观读锁
        Thread T2 = new Thread(lock::readLock, "线程2");
        T2.start();
        // 保证T2阻塞在读锁
        Thread.sleep(100);
        //中断线程T2
        //会导致线程T2所在CPU飙升
        T2.interrupt();
        T2.join();
    }

    /**
     * StampedLock 的读模板
     *
     * @throws InterruptedException
     */
    public static void stampedLockReadTemplate() throws InterruptedException {

        final StampedLock sl =
                new StampedLock();

        // 乐观读
        long stamp = sl.tryOptimisticRead();
        // 读入方法局部变量

        // 校验stamp
        if (!sl.validate(stamp)) {
            // 升级为悲观读锁
            stamp = sl.readLock();
            try {
                // 读入方法局部变量

            } finally {
                //释放悲观读锁
                sl.unlockRead(stamp);
            }
        }
        //使用方法局部变量执行业务操作

    }

    /**
     * StampedLock 的读模板
     *
     * @throws InterruptedException
     */
    public static void stampedLockWriteTemplate() throws InterruptedException {
        final StampedLock sl =
                new StampedLock();

        long stamp = sl.writeLock();
        try {
            // 写共享变量
            // ......
        } finally {
            sl.unlockWrite(stamp);
        }
    }
}
